package com.ck.ips.service.impl;

import com.ck.common.LoginFailRecord;
import com.ck.common.SessionUser;
import com.ck.common.model.OperationResult;
import com.ck.common.model.User;
import com.ck.core.cache.redis.RedisCacheDao;
import com.ck.core.constant.*;
import com.ck.core.util.JWTUtils;
import com.ck.ips.core.listener.event.LoginSuccessEvent;
import com.ck.ips.model.dto.sys.ModuleDTO;
import com.ck.ips.service.LoginService;
import com.ck.ips.service.sys.ModuleService;
import com.ck.ips.service.sys.RoleService;
import com.ck.ips.service.sys.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @Description: 系统用户service impl
* @Author: hf
* @Date:    2019/4/29 9:53
* @Version: 1.0
*/
@Service("loginService")
public class LoginServiceImpl implements LoginService {
	@Autowired
	private RedisCacheDao redisCacheDao;
	@Autowired
	private UserService userService;
	@Autowired
	private ApplicationContext applicationContext;
	@Autowired
	private ModuleService moduleService;
	@Autowired
	private RoleService roleService;
	@Override
	public OperationResult doLogin(String userName, String password, String imageCode, String remoteIP) {
		if ( StringUtils.isBlank(userName) ) {
			return OperationResult.newValidateFailOperationResult("用户名不能为空");
		}
		if ( StringUtils.isBlank(password) ) {
			return OperationResult.newValidateFailOperationResult("密码不能为空");
		}
		LoginFailRecord loginFailRecord = (LoginFailRecord) redisCacheDao.getCache(CacheConstant.CACHE_NAME_CK_USER_LOGIN_FAIL_RECORD, userName);
		if ( loginFailRecord != null && !canLogin(loginFailRecord) ) {
			return OperationResult.newValidateFailOperationResult("密码错误超过" + LoginFailRecord.MAX_FAIL_LOGIN_COUNT + "次，账户登录被冻结，还需等待："+ loginFailRecord.remainingTime());
		}

		User user = userService.getUserByUserName(userName);
		if (user == null) {
			return new OperationResult(ClientConstant.CODE_USER_NOT_REGIST,MsgConstant.USER_NAME_P_W_D_ERROR);
		}
		if ( !password.equals(user.getPassword()) ) {
			return OperationResult.newValidateFailOperationResult(MsgConstant.USER_NAME_P_W_D_ERROR);
			//return freeze(userName);
		}
		//验证通过后再验状态
		if (!Boolean.TRUE.equals(user.getStatus())) {
			return new OperationResult(ClientConstant.CODE_USER_FROZEN,"用户已被禁用，请联系管理员");
		}
		List<ModuleDTO> menus = moduleService.listMenuByUserId(user.getUserId(), UserType.SUPER.name().equals(user.getType()));
		if ( CollectionUtils.isEmpty(menus) ) {
			return OperationResult.newValidateFailOperationResult("该账户无任何权限，请联系管理员");
		}
		// 生成token
		Map<String,String> map = new HashMap<>();
		map.put("userName",user.getUserName());
		map.put("userId",user.getUserId().toString());
		map.put("realName",user.getRealName());
		map.put("userType",user.getType());
		String token = JWTUtils.generateJWTToken(map);

		SessionUser sessionUser = new SessionUser(user.getUserId(),user.getUserName(),user.getRealName(),token,user.getType());

		// 登录用户的关键(会话)信息放入缓存
		redisCacheDao.putCache(CacheConstant.CACHE_NAME_CK_TOKEN_CACHE_NAME, user.getUserName(), sessionUser);

		// 发布登录成功事件
		applicationContext.publishEvent(new LoginSuccessEvent(this,userName, remoteIP));

		Map<String,Object> loginResult = new HashMap<>();
		loginResult.put("token",token);
		loginResult.put("menu",menus);
		return OperationResult.newSuccessOperationResult(loginResult);
	}

	/**
	 * 冻结
	 * @param userName
	 */
	@Override
	public OperationResult freeze(String userName) {
		LoginFailRecord loginFailRecord = (LoginFailRecord) redisCacheDao.getCache(CacheConstant.CACHE_NAME_CK_USER_LOGIN_FAIL_RECORD, userName);
		if ( loginFailRecord == null ) {
			loginFailRecord = new LoginFailRecord(userName);
		}

		// 记录登录错误次数，冻结时间等
		loginFailRecord.log();

		// 将登录失败信息放入缓存
		redisCacheDao.putCache(CacheConstant.CACHE_NAME_CK_USER_LOGIN_FAIL_RECORD, userName,loginFailRecord);

		return new OperationResult(ClientConstant.CODE_PWD_NOT_RIGHT,"用户名或密码错误,您还有"+(LoginFailRecord.MAX_FAIL_LOGIN_COUNT - loginFailRecord.getFailCount())+"次机会,请重新输入");
	}

	/**
	 *
	 * @param userName
	 * @return
	 */
	@Override
	public OperationResult removeLoginFailCache(String userName) {
		// 删除冻结缓存信息
		redisCacheDao.deleteByKey(CacheConstant.CACHE_NAME_CK_USER_LOGIN_FAIL_RECORD, userName);
		// 移除图片验证码
		redisCacheDao.deleteByKey(CacheConstant.CACHE_NAME_CK_IMAGE_CODE_PREFIX + ImageCodeType.LOGIN.name(), userName);
		return OperationResult.newSuccessOperationResult();
	}

	@Override
	public OperationResult saveLoginSuccessRecord(LoginSuccessEvent loginSuccessEvent) {
		return userService.saveLoginSuccessRecord(loginSuccessEvent);
	}

	@Override
	public OperationResult doH5Login(String userName, String password, String imageCode, String remoteIP) {
		if ( StringUtils.isBlank(userName) ) {
			return OperationResult.newValidateFailOperationResult("用户名不能为空");
		}
		if ( StringUtils.isBlank(password) ) {
			return OperationResult.newValidateFailOperationResult("密码不能为空");
		}

		User user = userService.getUserByUserName(userName);
		if (user == null) {
			return new OperationResult(ClientConstant.CODE_USER_NOT_REGIST,"用户不存在，请重新输入");
		}
		if (!Boolean.TRUE.equals(user.getStatus())) {
			return new OperationResult(ClientConstant.CODE_USER_FROZEN,"用户已被禁用，请联系管理员");
		}
		if ( !password.equals(user.getPassword()) ) {
			return OperationResult.newValidateFailOperationResult(MsgConstant.USER_NAME_P_W_D_ERROR);
			//return freeze(userName);
		}

		List<Long> roleIds = userService.getRoleByUserId(user.getUserId());
		if ( roleIds == null || !roleIds.contains(BusinessConstant.INSTALLER_ROLE_ID) ) {
			return OperationResult.newValidateFailOperationResult("该用户非安装员角色");
		}

		// 生成token
		Map<String,String> map = new HashMap<>();
		map.put("userName",user.getUserName());
		map.put("userId",user.getUserId().toString());
		map.put("realName",user.getRealName());
		map.put("userType",user.getType());
		String token = JWTUtils.generateJWTToken(map);

		SessionUser sessionUser = new SessionUser(user.getUserId(),user.getUserName(),user.getRealName(),token,user.getType());

		// 登录用户的关键(会话)信息放入缓存
		redisCacheDao.putCache(CacheConstant.CACHE_NAME_CK_TOKEN_CACHE_NAME, user.getUserName(), sessionUser);

		// 发布登录成功事件
		applicationContext.publishEvent(new LoginSuccessEvent(this,userName, remoteIP));

		Map<String,Object> loginResult = new HashMap<>();
		loginResult.put("token",token);
		return OperationResult.newSuccessOperationResult(loginResult);
	}


	private boolean canLogin(LoginFailRecord loginFailRecord) {
		if ( loginFailRecord.needUnFreeze() ) {
			removeLoginFailCache(loginFailRecord.getUserName());
			return true;
		}
		return loginFailRecord.canLogin();
	}

}
